/**
 * Setvor project
 */
package setvor.npc.generator;

import static setvor.npc.generator.TypeMapper.getClassNativePrototype;
import static setvor.npc.generator.TypeMapper.getClassStubs;
import static setvor.npc.generator.TypeMapper.getTypeMap;

import java.io.*;
import java.util.Vector;

import setvor.npc.*;
import setvor.npc.generator.TypeMapper.TypeMap;

/**
 * This class can generate the specific stubs for specific class.
 * @author julatec
 *
 */
public final class NativeStubsGenerator {	
	
	/**
	 * This method takes a class and generate all stub and prototypes for 
	 * implement a native library. 
	 * @param clazz, the class for write the stubs and prototype files.
	 * @param classpath the directory where can find the .class files.
	 * @param output the directory where put the generated files.
	 * @throws IOException
	 * @throws SecurityException
	 * @throws NoSuchMethodException
	 */
	public static void GenerateFiles(
		Class<? extends NativeWriteable> clazz, File classpath, File output)
			throws IOException, SecurityException, NoSuchMethodException{
		TypeMap typeMap = getTypeMap(clazz);
		
		File stubsFile = new File(output, typeMap.getNativeFileName() + ".cpp");
		PrintWriter  stubsPrint = new PrintWriter (new FileWriter(stubsFile));  
		for(String line : getClassStubs(clazz))
			stubsPrint.println(line);
		stubsPrint.close();
		
		File prototypeFile = new File(output, File.separator + clazz.getSimpleName() + ".h");
		PrintWriter  prototypePrint = new PrintWriter (new FileWriter(prototypeFile));
		for(String line : getClassNativePrototype(clazz))
			prototypePrint.println(line);
		prototypePrint.close();
		
		Vector<String> command = new Vector<String>();
		command.addElement("javah");
		command.addElement(" -force ");
		command.addElement(" -classpath \"" + classpath.getAbsolutePath() + "\" ");
		command.addElement(" -o  \"" + 
				new File(output, typeMap.getNativeFileName() + ".h").getAbsolutePath() +
				"\" ");
		command.addElement(clazz.getName());
		String commandText = "";
		for(String arg : command)
			commandText += arg;
		
		try {
			Runtime.getRuntime().exec(commandText).waitFor();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * This is the list of parameters of this application.
	 * @author julatec
	 *
	 */
	private static enum Parameter{
		
		OUTPUT("-d"),
		CLASS_PATH("-cp"),
		HELP("-h"),
		CLASS("");
		
		/**
		 * The parameter command.
		 */
		public final String parameter;
		
		Parameter(String parameter){
			this.parameter = parameter;
		}
		
		/**
		 * This method return a parameter type of argument string.
		 * @param parameter
		 * @return
		 */
		public static Parameter getParameter(String parameter){
			for(Parameter param : values())
				if(param.parameter.equals(parameter))
					return param;
			return CLASS;
		}
		
	}
	
	@SuppressWarnings("unchecked")
	public static void main(String[] args) 
		throws ClassNotFoundException, SecurityException, IOException, NoSuchMethodException{
		
		String output  = ".";
		String classpath = ".";
		Vector<String> classes = new  Vector<String>();
		
		for(int i = 1 ; i < args.length - 1; i++){
			switch(Parameter.getParameter(args[i])){
				case OUTPUT:
					output = args[++i];
					break;
				case CLASS_PATH:
					classpath = args[++i];
					break;
				case CLASS:
				default:
					classes.addElement(args[i]);
			}
		}
		switch(Parameter.getParameter(args[args.length - 1])){
			case OUTPUT:
				System.out.println("Please write paramter for " + Parameter.OUTPUT.parameter);
				return;
			case CLASS_PATH:
				System.out.println("Please write paramter for " + Parameter.CLASS_PATH.parameter);
				return;
			case CLASS:
			default:
				classes.addElement(args[args.length - 1]);
		}
		
		File outputDir = new File(output);
		File classpathDir = new File(classpath);
		
		for(String className : classes){
			Class<?> clazz = Class.forName(className);
			GenerateFiles((Class<? extends NativeWriteable>) clazz, classpathDir, outputDir);
		}
	
	}
	
}
